﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.IO;
using System.Xml;

namespace WindowsFormsApplication1.WhoRequests
{
    public class WhoRequest
    {
        public ServerSocketData requesterServer;
        public int characterId;

        //We will only wait 3 seconds, and then assume any world servers that havent responded are down or having issues.
        private Timer timerRequestTimeout = new Timer(1000 * 3);

        private List<WhoResult> results = new List<WhoResult>();

        public WhoRequest(ServerSocketData requestingServer, int characterId)
        {
            this.requesterServer = requestingServer;
            this.characterId = characterId;

            timerRequestTimeout.AutoReset = false;
            timerRequestTimeout.Elapsed += new ElapsedEventHandler(timerRequestTimeout_Elapsed);
            timerRequestTimeout.Start();
        }

        private void killTimeout()
        {
            try
            {
                timerRequestTimeout.Stop();
                timerRequestTimeout.Dispose();
            }
            catch { }
        }

        private void timerRequestTimeout_Elapsed(object sender, ElapsedEventArgs e)
        {
            Managers.whoRequestManager.timeoutRequest(this);
        }

        public void sendRequests()
        {
            List<ServerSocketData> servers = Managers.socketConnectionsManager.GetServerSocketsCpy();
            servers.Remove(requesterServer);

            if (servers.Count == 0)
            {
                //Complete this request because there are no servers to query
                Managers.whoRequestManager.completeRequest(this);
                return;
            }

            //Build a list of results we expect to recieve
            foreach (ServerSocketData server in servers)
            {
                WhoResult result = new WhoResult(server);
                results.Add(result);
            }

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            xmldoc.WriteStartElement("globalwhorequest");
            xmldoc.WriteAttributeString("characterid", characterId.ToString());
            xmldoc.WriteEndElement();

            xmldoc.Flush();
            xmldoc.Close();
            stringWriter.Flush();
            string xmlMessage = stringWriter.ToString();

            //Send request out to all servers
            foreach (ServerSocketData ssd in servers)
            {
                //If send to this server failed, remove its expected result
                if (SocketConnectionsManager.sendToServer(ssd, xmlMessage) == false)
                {
                    lock (results)
                    {
                        foreach (WhoResult result in results)
                        {
                            if (result.server == ssd)
                            {
                                results.Remove(result);
                                break;
                            }
                        }
                    }
                }
            }
        }

        public void processResult(ServerSocketData fromServer, List<string> charactersOnline)
        {
            bool allResultsRecieved = true;
            lock (results)
            {
                //Look through all the expected results and find the matching server
                foreach (WhoResult result in results)
                {
                    if (result.server == fromServer)
                    {
                        //Flag this result as responded
                        result.hasResponded = true;

                        result.charactersOnline = charactersOnline;
                    }
                    if (result.hasResponded == false)
                        allResultsRecieved = false;
                }
            }
            if (allResultsRecieved)
                Managers.whoRequestManager.completeRequest(this);
        }

        public void timeoutRequest()
        {
            foreach (WhoResult result in results)
            {
                if (result.hasResponded == false)
                {
                    result.charactersOnline.Add("Server Timeout : " + result.server.server);
                    completeRequest();
                }
            }
        }
        public void completeRequest()
        {
            killTimeout();

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            //Sending the origional request result back, so origin is WS
            xmldoc.WriteStartElement("globalwhoresult");
            xmldoc.WriteAttributeString("characterid", characterId.ToString());

            lock (results)
            {
                foreach (WhoResult result in results)
                {
                    foreach (string characterOnline in result.charactersOnline)
                    {
                        xmldoc.WriteStartElement("characteronline");
                        xmldoc.WriteString(characterOnline);
                        xmldoc.WriteEndElement();
                    }
                }
            }

            xmldoc.WriteEndElement();
            xmldoc.Flush();
            xmldoc.Close();
            stringWriter.Flush();
            string xmlMessage = stringWriter.ToString();

            SocketConnectionsManager.sendToServer(requesterServer, xmlMessage);
        }
    }
}
